/*
 ------------------------------------------------------------------------------
 Copyright (C) 1996-2001 Id Software, Inc.

 This file is part of the Quake source code.

 The Quake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// color.h - color math library
//


#ifndef __MATH_COLOR_H__
#define __MATH_COLOR_H__


#define COLOR_MASK					63

// Color indices
#define COLOR_DEFAULT				52

#define COLOR_BLACK					0
#define COLOR_RED					1
#define COLOR_GREEN					2
#define COLOR_BLUE					3
#define COLOR_YELLOW				4
#define COLOR_CYAN					5
#define COLOR_MAGENTA				6
#define COLOR_WHITE					7

// Basic colors
extern glqVec4		colorDefault;

extern glqVec4		colorBlack;
extern glqVec4		colorRed;
extern glqVec4		colorGreen;
extern glqVec4		colorBlue;
extern glqVec4		colorYellow;
extern glqVec4		colorCyan;
extern glqVec4		colorMagenta;
extern glqVec4		colorWhite;
extern glqVec4		colorOrange;
extern glqVec4		colorChartreuse;
extern glqVec4		colorSpringGreen;
extern glqVec4		colorAzure;
extern glqVec4		colorViolet;
extern glqVec4		colorRose;
extern glqVec4		colorGray;

// Color table
extern glqVec4		color_table[64];

class glqColor {
public:
	byte			r;
	byte			g;
	byte			b;
	byte			a;

public:
					glqColor (void);
	explicit		glqColor (const byte l);
	explicit		glqColor (const byte l, const byte a);
	explicit		glqColor (const byte r, const byte g, const byte b);
	explicit		glqColor (const byte r, const byte g, const byte b, const byte a);

	byte			operator [] (const int index) const;
	byte &			operator [] (const int index);

	glqColor &		operator = (const glqColor &color);
	bool			operator == (const glqColor &color) const;
	bool			operator != (const glqColor &color) const;

	glqColor		operator + (const glqColor &color) const;
	glqColor		operator - (const glqColor &color) const;
	glqColor		operator * (const glqColor &color) const;

	glqColor &		operator += (const glqColor &color);
	glqColor &		operator -= (const glqColor &color);
	glqColor &		operator *= (const glqColor &color);

	void			Set (const byte l);
	void			Set (const byte l, const byte a);
	void			Set (const byte r, const byte g, const byte b);
	void			Set (const byte r, const byte g, const byte b, const byte a);
	void			Zero (void);
	bool			IsZeroed (void) const;
	void			Identity (void);
	bool			IsIdentity (void) const;
	void			Blend (const glqColor &src, const glqColor &dst, const float frac);
	void			Pack (const float l);
	void			Pack (const float l, const float a);
	void			Pack (const float r, const float g, const float b);
	void			Pack (const float r, const float g, const float b, const float a);
	void			Pack (const glqVec3 &rgb);
	void			Pack (const glqVec4 &rgba);
	void			Unpack (float &l) const;
	void			Unpack (float &l, float &a) const;
	void			Unpack (float &r, float &g, float &b) const;
	void			Unpack (float &r, float &g, float &b, float &a) const;
	void			Unpack (glqVec3 &rgb) const;
	void			Unpack (glqVec4 &rgba) const;

	const byte *	ToBytePtr (void) const;
	byte *			ToBytePtr (void);

	const char *	ToString (void) const;
};

INLINE glqColor::glqColor (void){

}

INLINE glqColor::glqColor (const byte l){

	this->r = l;
	this->g = l;
	this->b = l;
	this->a = 255;
}

INLINE glqColor::glqColor (const byte l, const byte a){

	this->r = l;
	this->g = l;
	this->b = l;
	this->a = a;
}

INLINE glqColor::glqColor (const byte r, const byte g, const byte b){

	this->r = r;
	this->g = g;
	this->b = b;
	this->a = 255;
}

INLINE glqColor::glqColor (const byte r, const byte g, const byte b, const byte a){

	this->r = r;
	this->g = g;
	this->b = b;
	this->a = a;
}

INLINE byte glqColor::operator [] (const int index) const {

	return (&r)[index];
}

INLINE byte &glqColor::operator [] (const int index){

	return (&r)[index];
}

INLINE glqColor &glqColor::operator = (const glqColor &color){

	r = color.r;
	g = color.g;
	b = color.b;
	a = color.a;

	return *this;
}

INLINE bool glqColor::operator == (const glqColor &color) const {

	if (r != color.r || g != color.g || b != color.b || a != color.a)
		return false;

	return true;
}

INLINE bool glqColor::operator != (const glqColor &color) const {

	if (r == color.r || g == color.g || b == color.b || a == color.a)
		return false;

	return true;
}

INLINE glqColor glqColor::operator + (const glqColor &color) const {

	glqColor	result;

	result.r = Min(r + color.r, 255);
	result.g = Min(g + color.g, 255);
	result.b = Min(b + color.b, 255);
	result.a = Min(a + color.a, 255);

	return result;
}

INLINE glqColor glqColor::operator - (const glqColor &color) const {

	glqColor	result;

	result.r = Max(r - color.r, 0);
	result.g = Max(g - color.g, 0);
	result.b = Max(b - color.b, 0);
	result.a = Max(a - color.a, 0);

	return result;
}

INLINE glqColor glqColor::operator * (const glqColor &color) const {

	glqColor	result;

	result.r = glqMath::FloatToByte(r * (color.r * (1.0f / 255.0f)));
	result.g = glqMath::FloatToByte(g * (color.g * (1.0f / 255.0f)));
	result.b = glqMath::FloatToByte(b * (color.b * (1.0f / 255.0f)));
	result.a = glqMath::FloatToByte(a * (color.a * (1.0f / 255.0f)));

	return result;
}

INLINE glqColor &glqColor::operator += (const glqColor &color){

	r = Min(r + color.r, 255);
	g = Min(g + color.g, 255);
	b = Min(b + color.b, 255);
	a = Min(a + color.a, 255);

	return *this;
}

INLINE glqColor &glqColor::operator -= (const glqColor &color){

	r = Max(r - color.r, 0);
	g = Max(g - color.g, 0);
	b = Max(b - color.b, 0);
	a = Max(a - color.a, 0);

	return *this;
}

INLINE glqColor &glqColor::operator *= (const glqColor &color){

	r = glqMath::FloatToByte(r * (color.r * (1.0f / 255.0f)));
	g = glqMath::FloatToByte(g * (color.g * (1.0f / 255.0f)));
	b = glqMath::FloatToByte(b * (color.b * (1.0f / 255.0f)));
	a = glqMath::FloatToByte(a * (color.a * (1.0f / 255.0f)));

	return *this;
}

INLINE void glqColor::Set (const byte l){

	this->r = l;
	this->g = l;
	this->b = l;
	this->a = 255;
}

INLINE void glqColor::Set (const byte l, const byte a){

	this->r = l;
	this->g = l;
	this->b = l;
	this->a = a;
}

INLINE void glqColor::Set (const byte r, const byte g, const byte b){

	this->r = r;
	this->g = g;
	this->b = b;
	this->a = 255;
}

INLINE void glqColor::Set (const byte r, const byte g, const byte b, const byte a){

	this->r = r;
	this->g = g;
	this->b = b;
	this->a = a;
}

INLINE void glqColor::Zero (void){

	r = 0;
	g = 0;
	b = 0;
	a = 0;
}

INLINE bool glqColor::IsZeroed (void) const {

	if (r != 0 || g != 0 || b != 0 || a != 0)
		return false;

	return true;
}

INLINE void glqColor::Identity (void){

	r = 255;
	g = 255;
	b = 255;
	a = 255;
}

INLINE bool glqColor::IsIdentity (void) const {

	if (r != 255 || g != 255 || b != 255 || a != 255)
		return false;

	return true;
}

INLINE void glqColor::Blend (const glqColor &src, const glqColor &dst, const float frac){

	int		scale, invScale;

	scale = glqMath::FloatToInt(256.0f * frac);
	invScale = 256 - scale;

	r = (src.r * invScale + dst.r * scale) >> 8;
	g = (src.g * invScale + dst.g * scale) >> 8;
	b = (src.b * invScale + dst.b * scale) >> 8;
	a = (src.a * invScale + dst.a * scale) >> 8;
}

INLINE const byte *glqColor::ToBytePtr (void) const {

	return &r;
}

INLINE byte *glqColor::ToBytePtr (void){

	return &r;
}


#endif	// __MATH_COLOR_H__